package com.validator;

import com.model.Result;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.ModelAndView;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * Created by hc on 2017/5/22.
 */
@Component
@Aspect
@Order(2)
@Slf4j
public class ValidateAspectHandel {

    @Around("@annotation(com.validator.ValidateGroup)")
    public Object validateAround(ProceedingJoinPoint joinPoint) throws Throwable  {
        boolean flag = false ;
        Map<String,Object> map=new HashMap<>();
        ValidateGroup an = null;
        Object[] args =  null ;
        Method method = null;
        Object target = null ;
        String methodName = null;
        try{
            // 方法名
            methodName = joinPoint.getSignature().getName();
            // 目标
            target = joinPoint.getTarget();
            // 根据方法名和类得到方法
            method = getMethodByClassAndName(target.getClass(), methodName);//得到拦截的方法
            args = joinPoint.getArgs();	//方法的参数
            assert method != null;
            an = method.getAnnotation(ValidateGroup.class);//得到方法上的注解
            if(an==null){
                flag=true;
            }else{
                map = validateFiled(an.fields() , args);
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        String status=(String) map.get("status");
        if("0".equals(status)){
            flag=true;
        }
        if(flag){
            log.info("属性验证通过");
            return joinPoint.proceed();
        }else {    //这里使用了Spring MVC ，所有返回值应该为Strng或ModelAndView
            log.info("属性验证未通过");
            assert method != null;
            Class<?> returnType = method.getReturnType();    //得到方法返回值类型
            if (returnType == ModelAndView.class) {
                ModelAndView mv = new ModelAndView();//返回错误页面
                assert an != null;
                if (!StringUtils.isEmpty(an.view())) {
                    mv.setViewName(an.view());
                }
                mv.addAllObjects(map);
                return mv;
            }else if(returnType==Map.class) {    //当使用Ajax的时候 可能会出现这种情况
                return map;
            } else if (returnType == Result.class) {    //  当类型等于项目中的Result时
                return new Result<>("", false, map.get("message"));
            } else {
                return null;
            }
        }
    }

    private Method getMethodByClassAndName(Class c, String methodName){
        Method[] methods = c.getDeclaredMethods();
        for (Method method : methods) {
            if(method.getName().equals(methodName)){
                return method ;
            }
        }
        return null;
    }

    private Map<String,Object> validateFiled(ValidateField[] validateFields, Object[] args) throws Exception {
        Map<String, Object> map = new HashMap<>();
        map.put("status", "0");
        for (ValidateField validateField : validateFields) {
            StringBuffer message = new StringBuffer();
            String showName = validateField.showName();
            String fileName = validateField.filedName();
            message.append("".equals(showName) ? fileName : showName);
            Object arg;

            // 判断fileName是否存在，若存在，则证明当前位置为一个对象
            if (StringUtils.isEmpty(fileName)) {
                arg = args[validateField.index()];
            } else {    // 从对象中取出对应的参数
                arg = getFieldByObjectAndFileName(args[validateField.index()], fileName);
            }

            // 若notNull为true，则判断对应的值是否为空
            if (validateField.notNull()) {
                if (arg == null || StringUtils.isEmpty(String.valueOf(arg))) {
                    map.put("status", "1");
                    map.put("message", message.append(" 不能为空!"));
                    return map;
                }
            } else {//如果该参数能够为空，并且当参数为空时，就不用判断后面的了 ，直接返回true
                if (arg == null || StringUtils.isEmpty(String.valueOf(arg))) {
                    continue;
                }
            }

            // 判断对应参数是否符合正则
            if (!StringUtils.isEmpty(validateField.regStr())) {//判断正则
                if (!(String.valueOf(arg)).matches(validateField.regStr())) {
                    map.put("status", "1");
                    map.put("message", message.append(" 格式不正确"));
                    return map;
                }
            }

            if (validateField.maxLen() > 0) {//判断字符串最大长度
                if (((String) arg).length() > validateField.maxLen()) {
                    map.put("status", "1");
                    map.put("message", message.append(" 不能超过").append(validateField.maxLen()).append("个字符!"));
                    return map;
                }
            }

            if (validateField.minLen() > 0) {//判断字符串最小长度
                if (((String) arg).length() < validateField.minLen()) {
                    map.put("status", "1");
                    map.put("message", message.append(" 不能少于").append(validateField.minLen()).append("个字符!"));
                    return map;
                }
            }

            if (validateField.maxVal() != -1) {//判断数值最大值
                if ((Integer) arg > validateField.maxVal()) {
                    map.put("status", "1");
                    map.put("message", message.append(" 数值不能大于").append(validateField.maxVal()));
                    return map;
                }
            }

            if (validateField.minVal() != -1) {//判断数值最小值
                if ((Integer) arg < validateField.minVal()) {
                    map.put("status", "1");
                    map.put("message", message.append(" 数值不能小于").append(validateField.minVal()));
                    return map;
                }
            }


            if (!StringUtils.isEmpty(validateField.values())) {//判断属性是否有固定值
                boolean flag = false;
                //获取分隔符
                String separator = validateField.separator();
                //属性的值
                String argValue = String.valueOf(arg);
                String values = validateField.values();
                if (!StringUtils.isEmpty(separator)) {//可以为多个值
                    String[] valueArray = values.split(separator);
                    if (valueArray != null && valueArray.length > 0) {
                        for (String val : valueArray) {
                            if (val.equals(argValue)) {
                                flag = true;
                                break;
                            }
                        }
                    }
                } else {
                    if (!argValue.equals(values)) {//只允许为一个值
                        map.put("status", "1");
                        map.put("message", message.append(" 的值只能是").append(values));
                        return map;
                    } else {
                        flag = true;
                    }
                }
                if (!flag) {
                    map.put("status", "1");
                    map.put("message", message.append(" 的值不在").append(values).append("内"));
                    return map;
                }
            }
        }
        return map;
    }



    private Object getFieldByObjectAndFileName(Object targetObj, String fileName) throws Exception{
        Object arg = targetObj ;
        arg=getField(arg,fileName);
        return arg ;
    }

    private Object getField(Object object,String fileName) throws Exception{
        Object obj=null;
        Class<?> clazz = object.getClass() ;
        try {
            PropertyDescriptor pd = new PropertyDescriptor(fileName, clazz);
            Method getMethod=pd.getReadMethod();//获取get方法
            obj=getMethod.invoke(object);
            log.info(clazz+":"+fileName+":"+obj);
        } catch (IntrospectionException e) {
            log.error(clazz+" 没有属性："+fileName);
        }

        return obj;
    }

}
